﻿using System;
using System.Collections.Generic;
using System.Data;

namespace Codemonk.Common.Data
{
    public class DbParameterBuilder<T> where T : IDataParameter, new()
    {
        public DbParameterBuilder()
        {
        }

        public DbParameterBuilder(int capacity)
        {
            _paras = new List<T>(capacity);
        }

        public DbParameterBuilder(IEnumerable<T> source)
        {
            _paras = new List<T>();
            _paras.AddRange(source);
        }

        private List<T> _paras;

        private List<T> Paras
        {
            get
            {
                if (_paras == null)
                    _paras = new List<T>();
                return _paras;
            }
        }
        public DbParameterBuilder<T> Add(T para)
        {
            if (para == null)
                throw new ArgumentException("参数para为null");
            CheckParameterName(para.ParameterName);
            Paras.Add(para);
            return this;
        }
        public DbParameterBuilder<T> Add(string parameterName, DbType? type = null)
        {
            T para = new T
            {
                ParameterName = parameterName
            };
            if (type.HasValue)
            {
                para.DbType = type.Value;
            }
            return Add(para);
        }
        public DbParameterBuilder<T> Add(string parameterName, object value, DbType? type = null)
        {
            T para = new T
            {
                ParameterName = parameterName,
                Value = value
            };
            if (type.HasValue)
            {
                para.DbType = type.Value;
            }
            return Add(para);
        }
        public DbParameterBuilder<T> Add(string parameterName, object value, ParameterDirection direction, bool isNullable, string sourceColumn, DbType? type = null, DataRowVersion sourceVersion = DataRowVersion.Default)
        {
            T para = new T
            {
                ParameterName = parameterName,
                Value = value,
                Direction = direction,
                SourceColumn = sourceColumn,
                SourceVersion = sourceVersion
            };
            if (type.HasValue)
            {
                para.DbType = type.Value;
            }
            return Add(para);
        }

        public DbParameterBuilder<T> SetValue(string parameterName, object value)
        {
            var paras = Paras;
            T item = default(T);
            foreach (var para in paras)
            {
                if (para.ParameterName.Equals(parameterName, StringComparison.Ordinal))
                {
                    item = para;
                    break;
                }
            }
            if (item != null)
                item.Value = value;
            return this;
        }
        public DbParameterBuilder<T> SetValue(int index, object value)
        {
            var paras = Paras;
            if (index > Count)
                throw new IndexOutOfRangeException("参数index越界");
            paras[index].Value = value;
            return this;
        }
        public DbParameterBuilder<T> SetValue(object value)
        {
            if (Count > 0)
                Paras[Count - 1].Value = value;
            return this;
        }
        public DbParameterBuilder<T> Set(Action<T> settet)
        {
            if (Count > 0)
                settet(Paras[Count - 1]);
            return this;
        }

        public int Count
        {
            get
            {
                return _paras == null ? 0 : _paras.Count;
            }
        }

        public bool IsCheckParameterName
        {
            get;
            set;
        }

        //[System.Diagnostics.Conditional("DEBUG")]
        private void CheckParameterName(string parameterName)
        {
            if (IsCheckParameterName)
                InnerCheckParameterName(parameterName);
        }

        private void InnerCheckParameterName(string parameterName)
        {
            if (string.IsNullOrEmpty(parameterName))
                throw new ArgumentException("参数parameterName为空");//空名称
            var paras = Paras;
            T item = default(T);
            foreach (var para in paras)
            {//已经有相同命名
                if (para.ParameterName.Equals(parameterName, StringComparison.Ordinal))
                {
                    item = para;
                    break;
                }
            }
            if (item != null)
                throw new ArgumentException("已经存在同名参数");
        }

        public DbParameterBuilder<T> AddRange(IEnumerable<T> paras)
        {
            Paras.AddRange(paras);
            return this;
        }

        public DbParameterBuilder<T> Union(DbParameterBuilder<T> helper)
        {
            if (helper != null && helper._paras != null)
            {
                var paras = helper._paras;
                var myParas = Paras;
                var isFind = false;
                foreach (var para in paras)
                {
                    if (myParas.Contains(para))
                        continue;
                    isFind = false;
                    foreach (var p in myParas)
                    {
                        if (p.ParameterName.Equals(para.ParameterName, StringComparison.Ordinal))
                        {
                            isFind = true;
                            break;
                        }
                    }
                    if (isFind)
                        continue;
                    Paras.Add(para);
                }
            }
            return this;
        }

        public DbParameterBuilder<T> Remove(T para)
        {
            Paras.Remove(para);
            return this;
        }

        public DbParameterBuilder<T> Remove(string parameterName)
        {
            var paras = Paras;
            T item = default(T);
            foreach (var para in paras)
            {
                if (para.ParameterName.Equals(parameterName, StringComparison.Ordinal))
                {
                    item = para;
                    break;
                }
            }
            if (item != null)
                paras.Remove(item);
            return this;
        }

        public DbParameterBuilder<T> Clear()
        {
            Paras.Clear();
            return this;
        }

        public IDataParameter[] ToArray()
        {
            var count = Count;
            if (count == 0)
                return null;
            IDataParameter[] ret = new IDataParameter[count];
            for (int i = 0; i < count; i++)
                ret[i] = Paras[i];
            return ret;
        }

        //public DbParameterBuilder ToBuilder()
        //{
        //    if (Count == 0) return null;
        //    var list = new List<System.Data.Common.DbParameter>();
        //    foreach (var item in _paras)
        //        list.Add(item as System.Data.Common.DbParameter);
        //    return new DbParameterBuilder(list);
        //}

        public IDbCommand AttachCommand(IDbCommand cmd)
        {
            if (cmd == null)
                throw new ArgumentException("参数cmd不能为空");
            var count = Count;
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                    cmd.Parameters.Add(Paras[i]);
            }
            return cmd;
        }

        public static DbParameterBuilder<T> operator +(DbParameterBuilder<T> h1, DbParameterBuilder<T> h2)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Union(h2);
        }

        public static DbParameterBuilder<T> operator -(DbParameterBuilder<T> h1, T para)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Remove(para);
        }

        public static DbParameterBuilder<T> operator -(DbParameterBuilder<T> h1, string parameterName)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Remove(parameterName);
        }

        public static DbParameterBuilder<T> operator +(DbParameterBuilder<T> h1, string parameterName)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Add(parameterName);
        }

        public static DbParameterBuilder<T> operator +(DbParameterBuilder<T> h1, T para)
        {
            if (h1 == null)
                throw new ArgumentException("参数h1为null");
            return h1.Add(para);
        }

        public static DbParameterBuilder<T> operator +(DbParameterBuilder<T> helper, IEnumerable<T> value)
        {
            if (helper == null)
                throw new ArgumentException("参数helper为null");
            return helper.AddRange(value);
        }

        public static implicit operator DbParameterBuilder<T>(List<T> value)
        {
            var helper = new DbParameterBuilder<T>();
            return helper.AddRange(value);
        }

        public static implicit operator DbParameterBuilder<T>(T[] value)
        {
            var helper = new DbParameterBuilder<T>();
            return helper.AddRange(value);
        }

    }
}
